﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.Linq.Extensions;
using Abp.Domain.Repositories;
using Microsoft.EntityFrameworkCore;
using Sunlit.House.Articles.Dto;
using Abp.Authorization;
using Sunlit.House.Authorization;

namespace Sunlit.House.Articles
{
    public class NewsCategoryAppService:HouseAppServiceBase,INewsCategoryAppService
    {
        private readonly IRepository<NewsCategory> _repository;

        public NewsCategoryAppService(IRepository<NewsCategory> repository)
        {
            _repository = repository;
        }
        [AbpAuthorize(PermissionNames.Pages_NewsCategory_Create)]
        public async Task<NewsCategoryDto> CreateAsync(CreateNewsCategoryInput input)
        {
            var cate = ObjectMapper.Map<NewsCategory>(input);

            if (input.ParentId.HasValue)
            {
                var parentCate = _repository.Get(input.ParentId.Value);
                cate.Layer = parentCate.Layer + 1;
            }

            await _repository.InsertAsync(cate);
            await CurrentUnitOfWork.SaveChangesAsync();
            return ObjectMapper.Map<NewsCategoryDto>(cate);
        }
        [AbpAuthorize(PermissionNames.Pages_NewsCategory_Delete)]
        public Task DeleteAsync(EntityDto input)
        {
            return _repository.DeleteAsync(input.Id);
        }
        [AbpAuthorize(PermissionNames.Pages_NewsCategory_Edit)]
        public async Task<NewsCategoryDto> UpdateAsync(UpdateNewsCategoryInput input)
        {
            var cate = await _repository.GetAsync(input.Id);
            ObjectMapper.Map(input, cate);
            await CurrentUnitOfWork.SaveChangesAsync();

            return ObjectMapper.Map<NewsCategoryDto>(cate);
        }
        public async Task<List<NewsCategoryDto>> GetCatesByParentId(int id)
        {
            var list = await _repository.GetAllListAsync(c => c.ParentId == id);

            return ObjectMapper.Map<List<NewsCategoryDto>>(list);
        }
        public async Task<List<NewsCategoryDto>> GetAllRootCates()
        {
            var list = await _repository.GetAllListAsync(c => !c.ParentId.HasValue);

            return ObjectMapper.Map<List<NewsCategoryDto>>(list);
        }
        #region 获取树形数据
        public async Task<List<NewsCategoryDto>> GetTreeData(GetTreeCateInput input)
        {
            var allCates = ObjectMapper.Map<List<NewsCategoryDto>>(await _repository.GetAllListAsync());
            if (!string.IsNullOrEmpty(input.Name))
            {
                allCates = allCates.Where(r => r.Name.Contains(input.Name)).ToList();
            }
            var rootCates = allCates.Where(r => r.ParentId == null).ToList();
            AddTreeNode(rootCates, allCates);

            return rootCates;

        }
        private void AddTreeNode(List<NewsCategoryDto> rootRegions, List<NewsCategoryDto> allRegions)
        {
            foreach (var rootRegion in rootRegions)
            {
                if (allRegions.Any(r => r.ParentId == rootRegion.Id))
                {
                    rootRegion.Children = allRegions.Where(rx => rx.ParentId == rootRegion.Id).ToList();
                    AddTreeNode(rootRegion.Children, allRegions);
                }
            }
        }
        #endregion
        /// <summary>
        /// Sort categories for tree representation
        /// </summary>
        /// <param name="source">Source</param>
        /// <param name="parentId">Parent category identifier</param>
        /// <param name="ignoreCategoriesWithoutExistingParent">A value indicating whether categories without parent category in provided category list (source) should be ignored</param>
        /// <returns>Sorted categories</returns>
        private IList<NewsCategoryDto> SortCategoriesForTree(IList<NewsCategoryDto> source, int? parentId = null,
            bool ignoreCategoriesWithoutExistingParent = false)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            var result = new List<NewsCategoryDto>();

            foreach (var cat in source.Where(c => c.ParentId == parentId).ToList())
            {
                result.Add(cat);
                result.AddRange(SortCategoriesForTree(source, cat.Id, true));
            }

            if (ignoreCategoriesWithoutExistingParent || result.Count == source.Count)
                return result;

            //find categories without parent in provided category source and insert them into result
            foreach (var cat in source)
                if (result.FirstOrDefault(x => x.Id == cat.Id) == null)
                    result.Add(cat);

            return result;
        }
        public async Task<IList<NewsCategoryDto>> GetAllListAsync()
        {
            var list = await _repository.GetAllListAsync();
            var listDto = ObjectMapper.Map<IList<NewsCategoryDto>>(list);

            foreach (var item in listDto)
            {
                if (item.Layer > 0)
                {
                    item.Name = "|" + item.Name.PadLeft(item.Name.Length + (item.Layer * 2), '-');
                }
            }

            return SortCategoriesForTree(listDto);
        }
        public async Task<IList<NewsCategoryDto>> GetAllInMenuAsync()
        {
            var list = await _repository.GetAllListAsync(n => n.ShowInMainMenu);
            return ObjectMapper.Map<IList<NewsCategoryDto>>(list);
        }
    }
}
